home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-11-05 | 50.0 KB | 2,188 lines |
- Path: xanth!nic.MR.NET!hal!cwjcc!mailrus!ulowell!page
- From: page@swan.ulowell.edu (Bob Page)
- Newsgroups: comp.sources.amiga
- Subject: v02i052: backup - file backup utility V2.01
- Message-ID: <10049@swan.ulowell.edu>
- Date: 4 Nov 88 22:20:16 GMT
- Organization: University of Lowell, Computer Science Dept.
- Lines: 2177
- Approved: page@swan.ulowell.edu
-
- Submitted-by: dillon@postgres.berkeley.edu (Matt Dillon)
- Posting-number: Volume 2, Issue 52
- Archive-name: dos/fs/backup201.1
-
- There are some serious bugs in backup/restore version V2.00.
- This is version 2.01, and fixes the following problems:
- (1) Restore would not put files in the proper sub-directory
- (2) Append mode for backup does not work
- These bugs were found by Jan Sven Trabandt.
-
- # This is a shell archive.
- # Remove everything above and including the cut line.
- # Then run the rest of the file through sh.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # backup.c
- # Makefile
- # backup.doc
- # This archive created: Fri Nov 4 17:11:15 1988
- cat << \SHAR_EOF > backup.c
-
- /*
- * BACKUP.C
- *
- * (C)Copyright 1986-88, Matthew Dillon, All Rights Reserved.
- * Permission is granted to distribute for non-profit only.
- *
- * Thanks to Jan Sven Trabandt for finding some major bugs!
- *
- * This program will backup a filesystem or directory, creating a single
- * output file which can later be RESTORE'd from. It is a quick way to
- * backup your work to a 'backup' disk.
- *
- * backup [options] path path path ... path [-ooutputfile]
- *
- * NOTE: if -o is not specified, not output file will be created
- *
- * options:
- *
- * -A ARCHIVE. Clear the archive bit on backed up files
- *
- * -U UPDATE. Backup only those files which have the archive bit
- * cleared.
- *
- * -f[#KB] Floppy... actually, this option is used to force the backup
- * program to automatically split up the backup files in #KB
- * sections (default 800). I.E. -f with nothing else will
- * use 800KB chunks. -f200 would use 200KB chunks, etc...
- *
- * PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
- * AND RESTORE
- *
- * -Fvol example: -FDF0: -FDF1: This command specifies the ordering
- * and number of (floppy) drives to backup to. This allows
- * one to change floppies in one drive while it is backing up
- * to another. It automatically cycles through the drives but
- * you still must specify an initial output file (-ofile) to
- * determine the base name for the files.
- *
- * This command also forces user prompting.
- *
- * PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
- * AND RESTORE
- *
- * -b backup (default if executable name is 'backup')
- *
- * -r restore (default if executable nam is 'restore')
- *
- * -a append to the destination file.
- *
- * -c Compress files during backup
- *
- * -s Only display directories as we go along.
- *
- * -l/-t (either option) Causes a RESTORE to only LIST the files,
- * not do an actual restore.
- *
- * -T (Restore) TIMESTAMP, COMMENT, AND PROTECTION BITS ONLY.
- * NO files are created. It is assumed the files already
- * exist. The timestamp and other fields are transfered
- * from the backup file to the already-restored files (useful
- * if the files were restored with a copy command that did
- * non copy the timestamps. Even if the backup file is old,
- * you can recover most of your time data).
- *
- * -S Silent. Don't display files or directories.
- *
- * -nKB Set buffer size to use, in KB.
- *
- * -v Verbose... Additionaly, display those files which will NOT
- * be backed up.
- *
- * -pPAT only file-paths matching this pattern are backed up. You
- * may specify more than one '-p' option.
- *
- * -dPAT file-paths matching this pattern are NOT backed up. you
- * may specify more than one '-d' option.
- *
- * -ofile Output File
- *
- * ---------------------------------------------------------------------
- *
- * destination file format:
- *
- * HDR = <HDR><N.B><datestamp> -Backup Date
- * VOL = <VOL><name_size.B><name> -VOLUME base
- * DDS = <DDS><name_size.B><name> -down-directory
- * END = <END><0.B> -up directory
- * DAT = <DAT><N.B><datestamp> -datestamp for file
- * PRO = <PRO><4.B><protection> -protection for file
- * COM = <COM><N.B><comment> -comment for file
- * FIL0= <FIL0><N.B><name><size.L><data> -uncompressed file
- * FIL1= <FIL1><N.B><name><size.L><usize.L><data> -compressed form #1
- * INC = <INC><12.B><ttlsize><strt><segsize> -next file is part of an
- * incomplete file
- */
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <local/typedefs.h>
-
- #define SDIR struct _SDIR
- #define SCOMP struct _SCOMP
-
- SCOMP {
- MNODE Node;
- uword Bytes; /* allocated bytes */
- uword N;
- };
-
- SDIR {
- MNODE Node; /* node in dir tree */
- ubyte Type; /* XDDS or XVOL */
- ubyte HaveFile; /* Something was backed up in here */
- char *Element; /* path element */
- };
-
- #define XVOL 0x01
- #define XDDS 0x02
- #define XEND 0x03
- #define XDAT 0x04
- #define XPRO 0x05
- #define XCOM 0x06
- #define XFIL0 0x87
- #define XFIL1 0x88
- #define XHDR 0x09
- #define XINC 0x0A
-
- ubyte Break;
- ubyte Restore;
- ubyte ListOnly;
- ubyte ShowFiles = 1;
- ubyte ShowDirs = 1;
- ubyte Verbose;
- ubyte Archive;
- ubyte Update;
- ubyte Append;
- ubyte Compress;
- ubyte TimeStampOnly;
- char *OutFile;
- long BacBytes;
- short BacCnt = 1;
-
- uword NumPicks;
- uword NumDels;
- char *Picks[32];
- char *Dels[32];
-
- char DirPath[256];
- short DPLen;
-
- long BufSize = 65536;
- long BufI;
- ubyte *Buf;
- long InBufSize = 8192;
- long InBufI, InBufN;
- ubyte *InBuf;
-
- MLIST VList; /* Volume list (-F), of NODEs */
- MLIST DList; /* Directory Stack */
- long CLen; /* Actual compressed file output length */
- MLIST CList; /* List of memory buffers */
- SCOMP *CWrite; /* Current memory buffer pointer */
-
- extern int Enable_Abort;
- extern void seekinputend();
- extern FIB *GetFileInfo();
- extern SCOMP *NewSComp();
- extern void *malloc(), *GetHead(), *GetTail(), *GetSucc(), *GetPred();
-
- main(ac, av)
- char *av[];
- {
- register short i, notdone;
- register char *str;
-
- NewList(&VList);
- NewList(&DList);
- NewList(&CList);
-
- Enable_Abort = 0;
-
-
- for (str = av[0] + strlen(av[0]); str >= av[0] && *str != '/' && *str != ':'; --str);
- ++str;
- if ((*str|0x20) == 'r')
- Restore = 1;
-
- if (ac == 1) {
- printf("Backup/Restore V2.01, (c)Copyright 1988 Matthew Dillon, All Rights Reserved\n", str);
- printf("%s -rbactlvASTU -d<pat> -p<pat> -f[#kb] -F<vol> -n<#kb> -ofile\n", str);
- }
-
- for (i = 1; i < ac; ++i) {
- str = av[i];
- if (*str != '-')
- continue;
- notdone = 1;
- ++str;
- while (notdone && *str) {
- switch(*str) {
- case 'r':
- Restore = 1;
- break;
- case 'b':
- Restore = 0;
- break;
- case 'a':
- Append = 1;
- break;
- case 'c':
- Compress = 1;
- break;
- case 'd':
- Dels[NumDels++] = str + 1;
- notdone = 0;
- break;
- case 'f':
- BacBytes = 800 * 1024;
- if (str[1] >= '0' && str[1] <= '9') {
- BacBytes = atoi(str+1) * 1024;
- notdone = 0;
- }
- break;
- case 'F':
- { /* strlen(str+1)+1 */
- register NODE *node = malloc(sizeof(NODE)+strlen(str));
- node->ln_Name = (char *)(node+1);
- strcpy(node+1, str+1);
- AddTail(&VList, node);
- }
- notdone = 0;
- break;
- case 'n':
- BufSize = atoi(str+1) * 1024;
- if (BufSize <= 0)
- BufSize = 65536;
- notdone = 0;
- break;
- case 'o':
- OutFile = str + 1;
- notdone = 0;
- break;
- case 'p':
- Picks[NumPicks++] = str + 1;
- notdone = 0;
- break;
- case 's':
- ShowFiles = 0;
- break;
- case 't':
- case 'l':
- ListOnly = 1;
- break;
- case 'v':
- Verbose= 1;
- break;
- case 'A':
- Archive= 1;
- break;
- case 'S':
- ShowFiles = 0;
- ShowDirs = 0;
- break;
- case 'T':
- TimeStampOnly = 1;
- break;
- case 'U':
- Update = 1;
- break;
- default:
- puts("failure");
- exit(20);
- }
- ++str;
- }
- }
- Buf = malloc(BufSize);
- if (Buf == NULL) {
- printf("Unable to malloc %ld bytes\n", BufSize);
- exit(20);
- }
- if (ListOnly)
- InBufSize = 512; /* small buffer to avoid read overhead */
- /* since we are skipping the meat */
-
- InBuf = malloc(InBufSize);
- if (InBuf == NULL) {
- printf("Unable to malloc %ld bytes\n", InBufSize);
- exit(20);
- }
-
- if (Restore)
- RestoreFiles(ac,av);
- else
- BackupFiles(ac,av);
- }
-
- long SaveLock;
-
- BackupFiles(ac, av)
- char *av[];
- {
- register short i;
- register char *str, *ptr;
- char notdone;
-
- if (OutFile && openoutput(OutFile, Append, ((BacBytes)?1:0)) == 0)
- exit(20);
- if (OutFile) { /* write header */
- DATESTAMP Date;
- DateStamp(&Date);
- outentry(XHDR, sizeof(DATESTAMP), &Date);
- }
-
- SaveLock = CurrentDir(DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
-
- for (i = 1; i < ac; ++i) {
- str = av[i];
- if (*str == '-')
- continue;
- /*
- * Push DDS entries for each name segment of the path
- */
-
- notdone = 1;
- while (notdone) {
- for (ptr = str; *ptr && *ptr != ':' && *ptr != '/'; ++ptr);
- switch(*ptr) {
- case '/': /* normal directory */
- *ptr = 0;
- PushDir(str, XDDS);
- str = ptr + 1;
- *ptr = '/';
- break;
- case ':': /* volume */
- *ptr = 0;
- PushDir(str, XVOL);
- str = ptr + 1;
- *ptr = ':';
- break;
- default: /* directory or file */
- {
- char *path = av[i];
- FIB *fib;
- long lock;
-
- if (fib = GetFileInfo(path, &lock)) {
- if (fib->fib_DirEntryType > 0) {
- if (str[0])
- PushDir(str, XDDS);
- lock = scan_directory(fib, lock);
- if (str[0])
- PopDirs(1);
- } else {
- lock = scan_file(fib, lock);
- }
- FreeFileInfo(fib, lock);
- } else {
- printf("Unable to get info for %s\n", av[i]);
- }
- }
- notdone = 0;
- break;
- }
- }
- PopDirs(-1);
- }
-
- UnLock(CurrentDir(SaveLock));
- if (OutFile)
- closeoutput();
- }
-
- DATESTAMP Date;
- char Comment[256];
- char Scr[256];
- long Protection;
- long IncSize; /* Size of entire file */
- long IncSeek; /* Seek offset into file */
- long IncLen; /* # bytes in this segment */
-
- RestoreFiles(ac, av)
- char *av[];
- {
- register short i;
- register char *str;
- char notdone;
- char havedate;
- char havepro;
- char havecom;
- char haveinc;
- long bytes;
- long actual;
- long lock;
-
- SaveLock = CurrentDir(lock = DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
-
- for (i = 1; i < ac; ++i) {
- str = av[i];
- if (*str == '-')
- continue;
- if (openinput(str) == 0) {
- printf("Unable to open %s for input\n", str);
- continue;
- }
- notdone = 1;
- havedate = havepro = havecom = haveinc = 0;
- while (notdone) {
- short c = oreadchar();
- short l = oreadchar();
- switch(c) {
- case -1:
- notdone = 0;
- break;
- case XVOL:
- oread(Scr, l);
- Scr[l] = 0;
- if (OutFile) { /* Restore to OutFile instead */
- register short j = strlen(OutFile);
- strcpy(Scr, OutFile);
- if (j && OutFile[j-1] == '/') {
- c = XDDS;
- Scr[j-1] = 0;
- } else if (j && OutFile[j-1] == ':') {
- c = XVOL;
- Scr[j-1] = 0;
- } else
- c = XDDS;
- }
- PushDir(Scr, c);
- if (ListOnly)
- break;
- lock = Lock(DirPath, SHARED_LOCK); /* DirPath incs ':' */
- if (lock == NULL && c == XDDS) {
- if (lock = CreateDir(Scr)) /* Scr excludes '/' */
- UnLock(lock);
- lock = Lock(Scr, SHARED_LOCK);
- }
- {
- SDIR *sd = GetTail(&DList);
- sd->HaveFile = 1; /* don't remove dir */
- }
- if (lock == NULL) {
- printf("Unable to create directory %s\n", Scr);
- notdone = 0;
- } else {
- UnLock(CurrentDir(lock));
- }
- break;
- case XDDS:
- oread(Scr, l);
- Scr[l] = 0;
- PushDir(Scr, XDDS);
- if (ListOnly)
- break;
- lock = Lock(Scr, SHARED_LOCK);
- if (lock == NULL) {
- if (lock = CreateDir(Scr))
- UnLock(lock);
- lock = Lock(Scr, SHARED_LOCK);
- } else {
- SDIR *sd = GetTail(&DList);
- sd->HaveFile = 1; /* don't remove dir */
- }
- if (lock == NULL) {
- printf("Unable to create directory %s\n", Scr);
- notdone = 0;
- } else {
- UnLock(CurrentDir(lock));
- }
- break;
- case XEND:
- {
- SDIR *sd = GetTail(&DList);
- ubyte type;
-
- c = 1;
- if (!sd)
- break;
- type = sd->Type;
- strcpy(Scr, sd->Element);
- c = PopDirs(1);
- if (ListOnly)
- break;
- if (type == XVOL) /* no parent directory */
- break;
- lock = ParentDir(lock);
- if (lock == NULL) {
- puts("Unable to ParentDir!");
- notdone = 0;
- } else {
- if (c == 0)
- DeleteFile(Scr);
- UnLock(CurrentDir(lock));
- }
- }
- break;
- case XDAT:
- if (l != sizeof(DATESTAMP)) {
- puts("expected sizeof datestamp");
- notdone = 0;
- break;
- }
- oread(&Date, l);
- havedate = 1;
- break;
- case XPRO:
- if (l != 4) {
- puts("Expected 4 bytes for protection");
- notdone = 0;
- break;
- }
- oread(&Protection, l);
- havepro = 1;
- break;
- case XCOM:
- oread(Comment, l);
- Comment[l] = 0;
- havecom = 1;
- break;
- case XFIL0:
- case XFIL1:
- if (!havepro)
- Protection = 0;
- if (!havecom)
- Comment[0] = 0;
- if (!havedate)
- DateStamp(&Date);
- if (!haveinc)
- IncSize = 0;
-
- oread(Scr, l);
- Scr[l] = 0;
- oread(&bytes, 4); /* length of file */
- actual = bytes;
- if (c == XFIL1) {
- oread(&actual, 4);
- bytes -= 4;
- }
- setinputbound(bytes);
- {
- short res = read_file(c, Scr, bytes, actual);
- seekinputend();
- if (res < 0)
- goto bend;
- }
- if (ListOnly)
- goto bend;
- if (Archive)
- SetProtection(Scr, Protection|FIBF_ARCHIVE);
- else
- SetProtection(Scr, Protection&~FIBF_ARCHIVE);
- if (havedate)
- setfiledate(Scr, &Date);
- if (havecom && Comment[0])
- SetComment(Scr, Comment);
- bend:
- havecom = havedate = havepro = haveinc = 0;
- break;
- case XHDR:
- if (l != sizeof(DATESTAMP)) {
- puts("expected sizeof datestamp");
- notdone = 0;
- break;
- }
- oread(&Date, l);
- printf(" ----- BACKUP ----- BACKUP DATE: %s\n", datetos(&Date, Scr, NULL));
- break;
- case XINC:
- if (l != 12) {
- puts("expected 12 bytes for XINC");
- notdone = 0;
- break;
- }
- oread(&IncSize, 4);
- oread(&IncSeek, 4);
- oread(&IncLen, 4);
- haveinc = 1;
- break;
- default:
- printf("Unknown Record Type: %02x\n", c);
- notdone = 0;
- break;
- }
- setinputbound(-1);
- if (mycheckbreak()) {
- Break = 1;
- notdone = 0;
- break;
- }
- }
- if (Break)
- break;
- }
- UnLock(CurrentDir(SaveLock));
- }
-
- FIB *
- GetFileInfo(path, plock)
- char *path;
- long *plock;
- {
- register long lock;
- register FIB *fib;
-
- *plock = NULL;
- if (lock = Lock(path, SHARED_LOCK)) {
- if (fib = malloc(sizeof(FIB))) {
- if (Examine(lock, fib)) {
- *plock = lock;
- return(fib);
- }
- free(fib);
- }
- UnLock(lock);
- }
- return(NULL);
- }
-
- FreeFileInfo(fib, lock)
- FIB *fib;
- long lock;
- {
- if (fib)
- free(fib);
- if (lock)
- UnLock(lock);
- }
-
-
- PushDir(element, type)
- char *element;
- {
- register SDIR *sd = malloc(sizeof(SDIR));
- register char *str = malloc(strlen(element)+1);
-
- strcpy(str, element);
- sd->Type = type;
- sd->HaveFile = 0;
- sd->Element = str;
- AddTail(&DList, sd);
- strcat(DirPath+DPLen, str);
- if (type == XVOL)
- strcat(DirPath+DPLen, ":");
- else
- strcat(DirPath+DPLen, "/");
- DPLen += strlen(DirPath+DPLen);
- }
-
- PopDirs(num)
- uword num;
- {
- register SDIR *sd, *sp;
- char lasthave = 0;
-
- while (num && (sd = GetTail(&DList))) {
- lasthave |= sd->HaveFile;
- if (sd->HaveFile) /* MUST write end-block */
- outentry(XEND, 0, NULL);
- if (sp = GetPred(sd))
- sp->HaveFile |= sd->HaveFile;
- Remove(sd);
- DPLen -= strlen(sd->Element) + 1;
- if (DPLen < 0) {
- puts("DPLEN ERROR");
- DPLen = 0;
- }
- DirPath[DPLen] = 0;
- free(sd->Element);
- free(sd);
- --num;
- }
- return(lasthave);
- }
-
- /*
- * SCAN_DIRECTORY() (CORE OF BACKUP)
- */
-
- scan_directory(dirfib, dirlock)
- FIB *dirfib;
- long dirlock;
- {
- register FIB *fib;
- long lock;
- long save = CurrentDir(dirlock);
-
- while (ExNext(dirlock, dirfib) && (fib = GetFileInfo(dirfib->fib_FileName, &lock))) {
- if (fib->fib_DirEntryType > 0) {
- PushDir(fib->fib_FileName, XDDS);
- if (ShowDirs)
- printf("%-40s (DIR)\n", DirPath);
- lock = scan_directory(fib, lock);
- PopDirs(1);
- } else {
- lock = scan_file(fib, lock);
- }
- FreeFileInfo(fib, lock);
- if (Break || mycheckbreak()) {
- Break = 1;
- break;
- }
- }
- CurrentDir(save);
- return(dirlock);
- }
-
- mycheckbreak()
- {
- if (SetSignal(0, (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
- puts(" ***** BREAK *****");
- return(1);
- }
- return(0);
- }
-
- /*
- * SCAN_FILE()
- *
- * If the file is accepted, write out pending directory entries, do
- * compression if any, and write out the file.
- */
-
- scan_file(fib, lock)
- FIB *fib;
- long lock;
- {
- long save;
- long n;
- char dbuf[32];
-
- strcat(DirPath, fib->fib_FileName);
-
- if (Update && (fib->fib_Protection & FIBF_ARCHIVE))
- goto nomatch;
- {
- register short i;
-
- for (i = 0; i < NumPicks; ++i) {
- if (wildcmp(Picks[i], DirPath))
- break;
- }
- if (i && i == NumPicks)
- goto nomatch;
-
- for (i = 0; i < NumDels; ++i) {
- if (wildcmp(Dels[i], DirPath))
- goto nomatch;
- }
- }
-
- if (ShowFiles)
- printf("%-40s %6ld %s\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
-
- {
- register SDIR *sd;
- SDIR *sdb = NULL;
-
- for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
- if (sd->HaveFile == 0)
- sdb = sd;
- }
- for (sd = sdb; sd; sd = GetSucc(sd)) {
- sd->HaveFile = 1;
- outentry(sd->Type, strlen(sd->Element), sd->Element);
- }
- }
- if (OutFile) {
- save = CurrentDir(lock);
- if (openinput("") == 0) {
- CurrentDir(save);
- printf("Unable to open %s\n", fib->fib_FileName);
- goto nomatch;
- }
- if (Compress && CompressFile(fib->fib_FileName, fib->fib_Size)) {
- if (OutFile && BacBytes && outbytes() + CLen > BacBytes) {
- if (newfile() == 0)
- goto skip1;
- }
- writeheaders(fib);
- outentry(XFIL1, strlen(fib->fib_FileName), fib->fib_FileName);
- CLen += 4;
- owrite(&CLen, 4);
- CLen -= 4;
- owrite(&fib->fib_Size, 4);
- transfer1(fib->fib_Size);
- } else {
- if (OutFile && BacBytes && outbytes() + fib->fib_Size > BacBytes) {
- if (newfile() == 0)
- goto skip1;
- }
- if (Compress)
- rollbackinput();
- writeheaders(fib);
- outentry(XFIL0, strlen(fib->fib_FileName), fib->fib_FileName);
- owrite(&fib->fib_Size, 4);
- transfer0(fib->fib_Size);
- }
- skip1:
- closeinput();
- CurrentDir(save);
- }
- if (Break)
- goto nomatch;
- if (Archive && !(fib->fib_Protection & FIBF_ARCHIVE)) {
- if (save = ParentDir(lock)) {
- UnLock(lock);
- save = CurrentDir(save);
- SetProtection(fib->fib_FileName, fib->fib_Protection | FIBF_ARCHIVE);
- lock = CurrentDir(save);
- }
- }
- DirPath[DPLen] = 0;
- return(lock);
- nomatch:
- if (Verbose)
- printf("%-40s (NOT ACCEPTED)\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
-
- DirPath[DPLen] = 0;
- return(lock);
- }
-
- writeheaders(fib)
- register FIB *fib;
- {
- outentry(XDAT, sizeof(DATESTAMP), &fib->fib_Date);
- outentry(XPRO, 4, &fib->fib_Protection);
- if (fib->fib_Comment[0])
- outentry(XCOM, strlen(fib->fib_Comment), fib->fib_Comment);
- }
-
- /*
- * (1) Write out XEND's to finish this archive,
- * (2) Open a new output file
- * (3) Write out XDDS's to build back to the current position
- */
-
- newfile()
- {
- {
- register SDIR *sd;
-
- for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
- if (sd->HaveFile)
- outentry(XEND, 0, NULL);
- }
- }
- ++BacCnt;
- if (OutFile && openoutput(OutFile, Append, 1) == 0) {
- Break = 1;
- return(0);
- }
- {
- register SDIR *sd;
- DATESTAMP Date;
- DateStamp(&Date);
- outentry(XHDR, sizeof(DATESTAMP), &Date);
- for (sd = GetHead(&DList); sd; sd = GetSucc(sd)) {
- if (sd->HaveFile)
- outentry(sd->Type, strlen(sd->Element), sd->Element);
- }
- }
- return(1);
- }
-
- read_file(type, fname, inbytes, outbytes)
- short type;
- char *fname;
- {
- char dbuf[32];
-
- strcat(DirPath, fname);
- {
- register short i;
-
- for (i = 0; i < NumPicks; ++i) {
- if (wildcmp(Picks[i], DirPath))
- break;
- }
- if (i && i == NumPicks) {
- if (Verbose)
- printf("%-40s (NOT ACCEPTED)\n", DirPath);
- goto nomatch;
- }
-
- for (i = 0; i < NumDels; ++i) {
- if (wildcmp(Dels[i], DirPath)) {
- if (Verbose)
- printf("%-40s (NOT ACCEPTED)\n", DirPath);
- goto nomatch;
- }
- }
- }
-
- printf("%-40s %6ld %6ld %s %s\n", DirPath, inbytes, outbytes, datetos(&Date, dbuf, NULL), Comment);
-
- if (ListOnly)
- goto nomatch;
- if (TimeStampOnly)
- goto matchskip;
-
- openoutput(fname, 0, 0);
- switch(type) {
- case XFIL0:
- transfer0(inbytes);
- break;
- case XFIL1:
- UnCompressFile(inbytes);
- transfer1(outbytes);
- break;
- }
- closeoutput();
- matchskip:
- DirPath[DPLen] = 0;
- return(1);
- nomatch:
- DirPath[DPLen] = 0;
- return(-1);
- }
-
- /*
- * FILE SUPPORT
- */
-
- static int Infd = -1;
- static int Outfd = -1;
- static long OutBytes;
-
- openoutput(name, append, enabtail)
- char *name;
- {
- char *ptr = name;
- static NODE *VNode; /* Volume node */
- long lock;
- extern int errno;
-
- if (Outfd >= 0) {
- dumpoutput();
- close(Outfd);
- Outfd = -1;
- }
- if (enabtail) {
- if (VNode)
- VNode = GetSucc(VNode);
- if (!VNode)
- VNode = GetHead(&VList);
- if (VNode) {
- ptr = malloc(strlen(VNode->ln_Name)+strlen(name)+8);
- sprintf(ptr, "%s%s.%02ld", VNode->ln_Name, name, BacCnt);
- } else {
- ptr = malloc(strlen(name)+8);
- sprintf(ptr, "%s.%02ld", name, BacCnt);
- }
- }
- OutBytes = 0;
- while (GetHead(&VList)) {
- short c;
- short d;
-
- fprintf(stderr, "Ready for %s (y=go,n=abort) -", ptr);
- fflush(stderr);
- if ((c = getc(stdin)) == EOF) {
- fprintf(stderr, "EOF, aborted\n");
- c = 'n';
- }
- while ((d = getc(stdin)) != EOF && d != '\n');
- if ((c|0x20) == 'y')
- break;
- if ((c|0x20) == 'n')
- goto skip;
- }
- if (enabtail && SaveLock) /* original directory */
- lock = CurrentDir(SaveLock);
- if (append) {
- Outfd = open(ptr, O_WRONLY|O_CREAT|O_APPEND);
- if (Outfd >= 0) {
- OutBytes = lseek(Outfd, 0L, 2);
- if (!append)
- lseek(Outfd, 0L, 0);
- }
- } else {
- Outfd = open(ptr, O_WRONLY|O_CREAT|O_TRUNC);
- }
- if (enabtail && SaveLock) /* back to before */
- CurrentDir(lock);
- if (Outfd < 0)
- printf("Unable to open output file %s (%ld)\n", ptr, errno);
- skip:
- BufI = 0;
- if (enabtail)
- free(ptr);
- return(Outfd >= 0);
- }
-
- oputc(v)
- char v;
- {
- ++OutBytes;
- if (Outfd >= 0) {
- if (BufI == BufSize)
- dumpoutput();
- Buf[BufI++] = v;
- }
- }
-
- owrite(buf, n)
- register char *buf;
- register long n;
- {
- register long avail;
-
- OutBytes += n;
- if (Outfd >= 0) {
- while (BufI + n > BufSize) {
- avail = BufSize - BufI;
- bmov(buf, Buf + BufI, avail);
- n -= avail;
- buf+= avail;
- BufI = BufSize;
- dumpoutput();
- }
- bmov(buf, Buf + BufI, n);
- BufI += n;
- }
- }
-
- dumpoutput()
- {
- if (Outfd >= 0 && BufI) {
- write(Outfd, Buf, BufI);
- BufI = 0;
- }
- }
-
- closeoutput()
- {
- if (Outfd >= 0) {
- dumpoutput();
- close(Outfd);
- Outfd = -1;
- }
- }
-
- outbytes()
- {
- return(OutBytes);
- }
-
- /*
- * <type><len><buf>
- */
-
- outentry(type, len, buf)
- ubyte type;
- ubyte len;
- ubyte *buf;
- {
- OutBytes += len + 2;
- if (Outfd >= 0) {
- if (BufI + len + 2 >= BufSize)
- dumpoutput();
- Buf[BufI+0] = type;
- Buf[BufI+1] = len;
- bmov(buf, Buf+BufI+2, len);
- BufI += len + 2;
- }
- }
-
- ulong OMax;
-
- openinput(name)
- char *name;
- {
- if (Infd >= 0)
- close(Infd);
- Infd = open(name, O_RDONLY);
- InBufI = InBufN = 0;
- OMax = -1;
- return(Infd >= 0);
- }
-
- closeinput()
- {
- if (Infd >= 0)
- close(Infd);
- Infd = -1;
- }
-
- void
- seekinputend()
- {
- register long inbuf = InBufI - InBufN;
- register long forward = OMax;
-
- if (forward > inbuf) {
- lseek(Infd, forward - inbuf, 1);
- OMax = InBufI = InBufN = 0;
- return;
- }
- InBufN += forward;
- }
-
- setinputbound(max)
- {
- OMax = max;
- }
-
- oread(buf, n)
- char *buf;
- long n;
- {
- long x = 0;
- long avail;
-
- if (Infd < 0)
- return(0);
- if (n > OMax)
- n = OMax;
-
- while (n > (avail = InBufI - InBufN)) {
- if (InBufN == -1)
- return(0);
- bmov(InBuf + InBufN, buf, avail);
- OMax-= avail;
- n -= avail;
- buf += avail;
- x += avail;
- InBufI = read(Infd, InBuf, InBufSize);
- InBufN = 0;
- if (InBufI <= 0) {
- InBufI = 0;
- return(x);
- }
- }
- bmov(InBuf + InBufN, buf, n);
- InBufN += n;
- x += n;
- OMax -= n;
- return(x);
- }
-
- oreadchar()
- {
- if (!OMax || Infd < 0)
- return(-1);
- if (InBufN == InBufI) {
- if (InBufN < 0)
- return(EOF);
- InBufI = read(Infd, InBuf, InBufSize);
- InBufN = 0;
- if (InBufI == 0) {
- InBufN = InBufI = -1;
- return(-1);
- }
- }
- return(InBuf[InBufN++]);
- }
-
- rollbackinput()
- {
- if (Infd >= 0)
- lseek(Infd, 0L, 0);
- InBufI = InBufN = 0;
- }
-
- mputc(v)
- char v;
- {
- register SCOMP *sc = CWrite;
-
- ++CLen;
- if (sc->N == sc->Bytes) {
- sc = GetSucc(sc);
- if (sc == NULL);
- sc = NewSComp();
- if (sc == NULL) {
- puts("SCOMP FAILED");
- return(0);
- }
- sc->N = 0;
- CWrite = sc;
- }
- ((char *)(sc + 1))[sc->N++] = v;
- }
-
- mwrite(buf, n)
- char *buf;
- long n;
- {
- register SCOMP *sc = CWrite;
- register long avail;
-
- CLen += n;
- while ((avail = sc->Bytes - sc->N) < n) {
- bmov(buf, (char *)(sc + 1) + sc->N, avail);
- buf += avail;
- n -= avail;
- sc->N = sc->Bytes;
- sc = GetSucc(sc);
- if (sc == NULL)
- sc = NewSComp();
- if (sc == NULL) {
- puts("SCOMP FAILED");
- return(0);
- }
- sc->N = 0;
- }
- bmov(buf, (char *)(sc + 1) + sc->N, n);
- sc->N += n;
- CWrite = sc;
- }
-
- SCOMP *
- NewSComp()
- {
- register SCOMP *sc = malloc(sizeof(SCOMP) + 8192);
-
- if (sc) {
- sc->Bytes = 8192;
- sc->N = 0;
- AddTail(&CList, sc);
- }
- return(sc);
- }
-
- transfer0(n)
- long n;
- {
- register long len;
-
- if (Outfd < 0)
- return(n);
- for (len = BufSize - BufI; n; len = BufSize - BufI) {
- if (len == 0) {
- dumpoutput();
- len = BufSize;
- }
- if (n < len)
- len = n;
- oread(Buf + BufI, len);
- BufI += len;
- n -= len;
- OutBytes += len;
- }
- }
-
- /*
- * Compression Routines
- *
- * transfer1(n) : Backup: copy compression buffer to output file
- */
-
- transfer1(a)
- {
- register long len;
- register SCOMP *sc = GetHead(&CList);
- register ubyte *ptr;
- long n = CLen;
-
- if (Outfd < 0)
- return(n);
- for (sc = GetHead(&CList); sc && n; sc = GetSucc(sc)) {
- len = sc->Bytes;
- ptr = (ubyte *)(sc + 1);
- if (n < len)
- len = n;
- n -= len;
- while (len > BufSize - BufI) {
- bmov(ptr, Buf + BufI, BufSize - BufI);
- ptr += BufSize - BufI;
- len -= BufSize - BufI;
- OutBytes += BufSize - BufI;
- BufI = BufSize;
- dumpoutput();
- }
- bmov(ptr, Buf + BufI, len);
- BufI += len;
- OutBytes += len;
- }
- if (n)
- puts("Unexpected EOF in compression file");
- }
-
- #asm
-
- ; Taken from my DRES.LIBRARY so we don't have to open the
- ; library.
-
- public _GetHead
- public _GetTail
- public _GetSucc
- public _GetPred
-
- _GetSucc:
- _GetHead: move.l 4(sp),A0
- move.l (A0),A0
- tst.l (A0)
- bne .gh1
- .ghz sub.l A0,A0
- .gh1 move.l A0,D0
- rts
-
- _GetTail: move.l 4(sp),A0
- move.l 8(A0),A0
- tst.l 4(A0)
- beq .ghz
- move.l A0,D0
- rts
-
- _GetPred: move.l 4(sp),A0
- move.l 4(A0),A0
- tst.l 4(A0)
- beq .ghz
- move.l A0,D0
- rts
-
- #endasm
-
- #define ngetchar() oreadchar()
- #define nputchar(n) mputc(n)
-
- #ifndef min
- #define min(a,b) ((a>b) ? b : a)
- #endif
-
- #define BITS 13
-
- #if BITS == 16
- #define HSIZE 69001 /* 95% occupancy */
- #endif
- #if BITS == 15
- #define HSIZE 35023 /* 94% occupancy */
- #endif
- #if BITS == 14
- #define HSIZE 18013 /* 91% occupancy */
- #endif
- #if BITS == 13
- #define HSIZE 9001 /* 91% occupancy */
- #endif
- #if BITS <= 12
- #define HSIZE 5003 /* 80% occupancy */
- #endif
-
- typedef long code_int;
- typedef long count_int;
- typedef unsigned char char_type;
-
- #define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
- #define INIT_BITS 9 /* initial number of bits/code */
-
- int n_bits; /* number of bits/code */
- int maxbits; /* user settable max # bits/code */
- code_int maxcode; /* maximum code, given n_bits */
- code_int maxmaxcode; /* should NEVER generate this code */
-
- count_int htab[HSIZE];
- uword codetab[HSIZE];
-
- #define htabof(i) htab[i]
- #define codetabof(i) codetab[i]
-
- code_int hsize = HSIZE; /* for dynamic table sizing */
-
- #define tab_prefixof(i) codetabof(i)
- #define tab_suffixof(i) ((char_type *)(htab))[i]
- #define de_stack ((char_type *)&tab_suffixof(1<<BITS))
-
- code_int free_ent; /* first unused entry */
-
- code_int getcode();
-
- #define CHECK_GAP 10000 /* ratio check interval */
-
- int block_compress = 1;
- int clear_flg;
- long ratio;
- count_int checkpoint;
-
- /*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-
- #define FIRST 257 /* first free entry */
- #define CLEAR 256 /* table clear output code */
-
- static int offset;
- long int in_count = 1; /* length of input */
-
- /*
- * Compress a file to memory-buffers and return TRUE if the compressed
- * size is smaller than the actual size.
- */
-
- CompressFile(name, fsize)
- {
- long fcode;
- code_int i = 0;
- int c;
- code_int ent;
- int disp;
- code_int hsize_reg;
- int hshift;
-
- if (wildcmp("*.Z", name) || wildcmp("*.ARC", name) || wildcmp("*.ZOO", name)) {
- printf(" Will not compress %s\n", name);
- return(0);
- }
-
- CLen = 0;
- CWrite = GetHead(&CList);
- if (CWrite == NULL)
- CWrite = NewSComp();
- CWrite->N = 0;
-
- bzero(htab, sizeof(htab));
- bzero(codetab, sizeof(codetab));
-
- hsize = HSIZE;
- if ( fsize < (1 << 12) )
- hsize = min ( 5003, HSIZE );
- else if ( fsize < (1 << 13) )
- hsize = min ( 9001, HSIZE );
- else if ( fsize < (1 << 14) )
- hsize = min ( 18013, HSIZE );
- else if ( fsize < (1 << 15) )
- hsize = min ( 35023, HSIZE );
- else if ( fsize < 47000 )
- hsize = min ( 50021, HSIZE );
-
- offset = clear_flg = ratio = 0;
- in_count = 1;
- checkpoint = CHECK_GAP;
- n_bits = INIT_BITS; /* number of bits/code */
- maxbits = BITS; /* user settable max # bits/code */
- maxcode = MAXCODE(INIT_BITS); /* maximum code, given n_bits */
- maxmaxcode = 1 << BITS; /* should NEVER generate this code */
- free_ent = ((block_compress) ? FIRST : 256 );
-
- ent = ngetchar();
-
- hshift = 0;
- for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
- hshift++;
- hshift = 8 - hshift; /* set hash code range bound */
-
- hsize_reg = hsize;
- cl_hash((count_int)hsize_reg); /* clear hash table */
-
- while ((c = ngetchar()) != EOF) {
- in_count++;
- fcode = (long) (((long) c << maxbits) + ent);
- i = ((c << hshift) ^ ent); /* xor hashing */
-
- if (htabof (i) == fcode) {
- ent = codetabof(i);
- continue;
- } else if ((long)htabof (i) < 0) /* empty slot */
- goto nomatch;
- disp = hsize_reg - i; /* secondary hash (after G. Knott) */
- if (i == 0)
- disp = 1;
- probe:
- if ((i -= disp) < 0)
- i += hsize_reg;
-
- if (htabof (i) == fcode) {
- ent = codetabof(i);
- continue;
- }
- if ((long)htabof (i) > 0)
- goto probe;
- nomatch:
- output ((code_int) ent);
- ent = c;
- if (free_ent < maxmaxcode) {
- codetabof(i) = free_ent++; /* code -> hashtable */
- htabof(i) = fcode;
- }
- else if ((count_int)in_count >= checkpoint && block_compress)
- cl_block ();
- }
-
- /*
- * Put out the final code.
- */
-
- output((code_int)ent);
- output((code_int)-1);
-
- return(CLen < fsize);
- }
-
- static char buf[BITS];
-
- char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
- char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-
- output( code )
- code_int code;
- {
- register int r_off = offset, bits= n_bits;
- register char * bp = buf;
-
- if ( code >= 0 ) {
- /*
- * Get to the first byte.
- */
- bp += (r_off >> 3);
- r_off &= 7;
- /*
- * Since code is always >= 8 bits, only need to mask the first
- * hunk on the left.
- */
- *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
- bp++;
- bits -= (8 - r_off);
- code >>= 8 - r_off;
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if ( bits >= 8 ) {
- *bp++ = code;
- code >>= 8;
- bits -= 8;
- }
- /* Last bits. */
- if(bits)
- *bp = code;
-
- offset += n_bits;
- if (offset == (n_bits << 3)) {
- bp = buf;
- bits = n_bits;
- mwrite(bp, bits);
- bp += bits;
- bits = 0;
- offset = 0;
- }
-
- /*
- * If the next entry is going to be too big for the code size,
- * then increase it, if possible.
- */
-
- if (free_ent > maxcode || (clear_flg > 0)) {
- /*
- * Write the whole buffer, because the input side won't
- * discover the size increase until after it has read it.
- */
- if (offset > 0)
- mwrite(buf, n_bits);
- offset = 0;
-
- if (clear_flg) {
- n_bits = INIT_BITS;
- maxcode = MAXCODE(INIT_BITS);
- clear_flg = 0;
- } else {
- n_bits++;
- if (n_bits == maxbits)
- maxcode = maxmaxcode;
- else
- maxcode = MAXCODE(n_bits);
- }
- }
- } else {
- /*
- * At EOF, write the rest of the buffer.
- */
- if (offset > 0)
- mwrite(buf, (offset + 7) / 8);
- offset = 0;
- }
- }
-
-
- char *
- xrindex(s, c) /* For those who don't have it in libc.a */
- register char *s, c;
- {
- char *p;
- for (p = NULL; *s; s++) {
- if (*s == c)
- p = s;
- }
- return(p);
- }
-
-
- cl_block() /* table clear for block compress */
- {
- register long int rat;
-
- checkpoint = in_count + CHECK_GAP;
-
- if (in_count > 0x007fffff) { /* shift will overflow */
- rat = CLen >> 8;
- if (rat == 0) { /* Don't divide by zero */
- rat = 0x7fffffff;
- } else {
- rat = in_count / rat;
- }
- } else {
- rat = (in_count << 8) / CLen; /* 8 fractional bits */
- }
- if (rat > ratio) {
- ratio = rat;
- } else {
- ratio = 0;
- cl_hash ( (count_int) hsize );
- free_ent = FIRST;
- clear_flg = 1;
- output ( (code_int) CLEAR );
- }
- }
-
- cl_hash(hsize) /* reset code table */
- register count_int hsize;
- {
- register count_int *htab_p = htab+hsize;
- register long i;
- register long m1 = -1;
-
- i = hsize - 16;
- do { /* might use Sys V memset(3) here */
- *(htab_p-16) = m1;
- *(htab_p-15) = m1;
- *(htab_p-14) = m1;
- *(htab_p-13) = m1;
- *(htab_p-12) = m1;
- *(htab_p-11) = m1;
- *(htab_p-10) = m1;
- *(htab_p-9) = m1;
- *(htab_p-8) = m1;
- *(htab_p-7) = m1;
- *(htab_p-6) = m1;
- *(htab_p-5) = m1;
- *(htab_p-4) = m1;
- *(htab_p-3) = m1;
- *(htab_p-2) = m1;
- *(htab_p-1) = m1;
- htab_p -= 16;
- } while ((i -= 16) >= 0);
- for ( i += 16; i > 0; i-- )
- *--htab_p = m1;
- }
-
- UnCompressFile(insize)
- {
- register char_type *stackp;
- register int finchar;
- register code_int code, oldcode, incode;
-
- /*
- * As above, initialize the first 256 entries in the table.
- */
-
- bzero(htab, sizeof(htab));
- bzero(codetab, sizeof(codetab));
-
- offset = clear_flg = ratio = 0;
- in_count = 1;
- checkpoint = CHECK_GAP;
- n_bits = INIT_BITS; /* number of bits/code */
- maxbits = BITS; /* user settable max # bits/code */
- maxcode = MAXCODE(INIT_BITS); /* maximum code, given n_bits */
- maxmaxcode = 1 << BITS; /* should NEVER generate this code */
-
- for ( code = 255; code >= 0; code-- ) {
- tab_prefixof(code) = 0;
- tab_suffixof(code) = (char_type)code;
- }
- free_ent = ((block_compress) ? FIRST : 256 );
-
- finchar = oldcode = getcode();
- if (oldcode == -1) /* EOF already? */
- return; /* Get out of here */
- oputc((char)finchar); /* first code must be 8 bits = char */
- stackp = de_stack;
-
- while ((code = getcode()) > -1) {
- if ((code == CLEAR) && block_compress) {
- for (code = 255; code >= 0; code--)
- tab_prefixof(code) = 0;
- clear_flg = 1;
- free_ent = FIRST - 1;
- if ((code = getcode()) == -1) /* O, untimely death! */
- break;
- }
- incode = code;
- /*
- * Special case for KwKwK string.
- */
- if (code >= free_ent) {
- *stackp++ = finchar;
- code = oldcode;
- }
-
- /*
- * Generate output characters in reverse order
- */
- while ( code >= 256 ) {
- *stackp++ = tab_suffixof(code);
- code = tab_prefixof(code);
- }
- *stackp++ = finchar = tab_suffixof(code);
-
- /*
- * And put them out in forward order
- */
- do
- oputc (*--stackp);
- while (stackp > de_stack);
-
- /*
- * Generate the new entry.
- */
- if ((code=free_ent) < maxmaxcode) {
- tab_prefixof(code) = (unsigned short)oldcode;
- tab_suffixof(code) = finchar;
- free_ent = code+1;
- }
- /*
- * Remember previous code.
- */
- oldcode = incode;
- }
- }
-
- code_int
- getcode()
- {
- /*
- * On the VAX, it is important to have the register declarations
- * in exactly the order given, or the asm will break.
- */
-
- register code_int code;
- static int offset = 0, size = 0;
- static char_type buf[BITS];
- register int r_off, bits;
- register char_type *bp = buf;
-
- if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
- /*
- * If the next entry will be too big for the current code
- * size, then we must increase the size. This implies reading
- * a new buffer full, too.
- */
- if ( free_ent > maxcode ) {
- n_bits++;
- if ( n_bits == maxbits )
- maxcode = maxmaxcode; /* won't get any bigger now */
- else
- maxcode = MAXCODE(n_bits);
- }
- if ( clear_flg > 0) {
- maxcode = MAXCODE (n_bits = INIT_BITS);
- clear_flg = 0;
- }
- size = oread(buf, n_bits);
- if (size <= 0)
- return -1; /* end of file */
- offset = 0;
- size = (size << 3) - (n_bits - 1);
- }
- r_off = offset;
- bits = n_bits;
-
- /*
- * Get to the first byte.
- */
- bp += (r_off >> 3);
- r_off &= 7;
- /* Get first part (low order bits) */
-
- code = (*bp++ >> r_off);
-
- bits -= (8 - r_off);
- r_off = 8 - r_off; /* now, offset into code word */
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if ( bits >= 8 ) {
- code |= *bp++ << r_off;
- r_off += 8;
- bits -= 8;
- }
- /* high order bits. */
- code |= (*bp & rmask[bits]) << r_off;
-
- offset += n_bits;
-
- return code;
- }
-
- SHAR_EOF
- cat << \SHAR_EOF > Makefile
-
- # Makefile for backup
-
- SYMS= include:symbols.m
- SYMC= include:local/makesymbols.c
- CFLAGS= +L +I$(SYMS)
- LFLAGS= +Q
- DD= srcc:
- OD= T:
-
- $(DD)backup: backup.c
- cc $(CFLAGS) backup.c -o $(OD)backup.o
- ln +Q $(OD)backup.o -lsup32 -lc32 -o $(DD)backup
- delete $(OD)backup.o
-
- $(SYMS): $(SYMC)
- make -f include:local/Makefile
-
- SHAR_EOF
- cat << \SHAR_EOF > backup.doc
-
- BACKUP.DOC
-
- V2.01
-
- 3 November 1988
- (c)Copyright 1988, Matthew Dillon, All Rights Reserved
- Freely Distributable for non-profit only
- (this is the same document as backup.doc v2.00)
-
- (I)
- OVERVIEW
-
- Backup and Restore (same executable, just renamed) allow you to backup
- any directory tree with optional compression, and later extract all
- or part of the tree. The protection, date, and file comment is saved
- with each file.
-
- SEE SECTION (6), FLOPICAL BACKUP, for options pertaining to backing
- up directly to floppies.
-
- LIMITATIONS: When using -c (compress), the entire result of the
- compressed file must fit into memory. Any files (after compression,
- if any) larger than a floppy when backing up to floppies cannot be
- handled yet.
-
-
- (I)
- INSTALLATION
-
- Copy the (1) executable to your C: directory twice, naming one
- 'Backup' and the other 'Restore'. The program looks at the first
- character of its name to determine whether the default is to backup
- or restore. If you don't have the space, all is not lost ... you
- simply need to specify backup or restore explicitly with the options
- (-b or -r).
-
- (2)
- EXOTIC FEATURES
-
- Backup does not write directory trees which contain no files. Thus,
- when doing incremental backups on a large hard disk, the structure of
- directory sub-trees which have no new files in them will not be
- written. So if you only modified a couple of files since the last
- backup, there won't be 50K of structure-overhead.
-
- You can specify compression (-c) in the backup. All files are
- compressed (there must be enough RAM to hold the largest file in
- its compressed state). Those files which would turn out larger after
- compression than before are NOT compressed. Certain file suffixes
- cause the compression attempt to be skipped entire: .Z, .ARC, and .ZOO
- files
-
- IT IS SUGGESTED YOU USE THE COMPRESSION FEATURE EVEN THOUGH IT
- SLOWS DOWN THE BACKUP. The resulting backup file will be
- significantly reduced in size. Even though a full backup will
- take a long time, you only do that every once in a while and
- as incremental backups are shorter, they take much less time.
-
- 'Pick' patterns are supported (backup only paths which match the
- specified patterns), and 'Discard' patterns are supported (do not backup
- paths which match the specified patterns). Discard patterns override
- Pick patterns.
-
- (3)
- OPTIONS
-
- Here is a list of Backup/Restore options.
-
- -A ARCHIVE. (Backup) Causes the archive bit to be cleared
- on files being backed up. (Protection bit -> 1)
-
- (Restore): If specified, the archive bit is cleared on
- restored files. Otherwise the archive bit will be set,
- causing the files to be backed up again on the next
- incremental backup.
-
- -U UPDATE. (Backup) Restricts the backup to only those files
- which have the archive bit set. (Protection bit == 0)
-
- -b BACKUP (this is the default if the first character in
- the executable is a 'b')
-
- -r RESTORE (this is the default if the first character in
- the executable is an 'r')
-
- -a APPEND (Backup) Cause the backup to be appended to
- the specified (-o) file rather than overwriting it. Useful
- for incremental backups.
-
- -c COMPRESS (Backup) Cause all files to be compressed, if
- possible. Restore automatically decompresses files which
- have been compressed. This is the same algorithm used
- in the UNIX compress command.
-
- NO COMPRESSION WILL EVEN BE ATTEMPED ON FILES WITH THE
- FOLLOWING SUFFIXES: .Z .ARC .ZOO
-
- -f[#kb] Turn on backup fragmentation and specify the fragment size,
- default 800K (for backing up to floppies). NOTE: Currently,
- files larger than the fragment size cannot be backed up!
-
- Note: a suffix is added to the file name w/ a sequence
- number, but each fragment is a complete backup file unto
- itself and may be restored out of order.
-
- Any numerical value specified is in K, i.e. -f800 == 800K
-
- -Fvol: Add the volume (df0:, df1:, etc..) to the drive sequencing
- list. The idea is to specify several -F options which are
- cycled through and prefix each fragment. This also
- enables prompting... the program prompts whenever it
- switches to the next fragment.
-
- If -F is not specified at all and -f is, no prompting
- occurs.
-
- -s Only display directories as we go along
-
- -S Silent... don't display files or directories
-
- -v Verbose... display those files which will NOT be backed
- up as well as those that will.
-
- -l/-t (both do the same thing). (Restore) LIST the archive
- only, do not do an actual restore.
-
- -T (Restore) Restore ONLY the timestamp, comment, and
- protection fields. This is incredibly useful to
- restore timestamp information to files that already
- exist. NO files are overwritten or created on the
- destination volume(s).
-
- -n# (Backup) Sets the output buffer size, in KILOBYTES.
- Default is 64.
-
- -pPAT (Backup) Restrict the backup to files which match the
- specified pattern. Up to 32 patterns may be specified.
-
- (Restore) Extract only those files which match the
- specified pattern.
-
- NOTE: The pattern is matched with the COMPLETE PATH as
- shown in the -t option. '*' and '?' wildcarding is supported
-
- -dPAT (Backup) Do not backup files which match the specified
- pattern. Up to 32 patterns may be specified.
-
- (Restore) Do not extract files which match the specified
- pattern.
-
- NOTE: The pattern is matched with the COMPLETE PATH as
- shown in the -t option. '*' and '?' wildcarding is supported.
-
- -oFILE (Backup) Specify the OUTPUT FILE for a backup. IF NO
- OUTPUT FILE IS SPECIFIED, NO OUTPUT FILE IS CREATED. I.E.
- you can take a second pass just to clear the archive bit.
-
- (Restore) Specify the directory to place the restored
- directory tree. (This overrides the volume the backup
- was saved from). If no directory specified, the original
- volume used in the backup will be restored to. If no
- volume was specified in the backup but rather a relative
- path was, the restore will be relative to the current
- directory.
-
- (4)
- STANDARD METHOD OF BACKING UP
-
- Note that with combinations of -o, -A, and -U, you have many choices
- available to you when backing up files. For hard disks, backups are
- normally done in two phases:
-
- -Once a month do a complete backup of your hard disk
- -Every day do a much smaller 'incremental' backup which backs
- up only those files which have been modified/created since the
- last backup.
-
- The master backup, plus the N incremental backups together
- reconstruct your disk up to the moment. After a while the
- number of incremental backups will be so great (and messy),
- that you will want to do another complete backup and start
- again.
-
- IN THIS WAY, the COMPRESS option can be put to good use. The
- incremental backups are usually small, and can be compressed
- relatively quickly. The complete backup should also be compressed
- (-c in case you forgot) though this will take a much longer time...
- but then again the complete backup is not done every day.
-
- UPDATING THE ARCHIVE BIT ON THE FLY VERSES TAKING A SECOND PASS.
- Updating the archive bit involves writing to the disk. For complete
- safety you probably do NOT want to update the archive bit while you
- are backing up the files in question. The following two-pass method
- works well:
-
- (COMPLETE BACKUP)
-
- backup -c -d"*.o" volume: -ooutput
- backup -A volume:
-
- (INCREMENTAL BACKUP)
-
- backup -U -c -d"*.o" volume: -ooutput
- backup -A volume:
-
- The -d option is saying "Don't backup all those object modules I left
- laying around".
-
- The first command backs up only those files which have be modified
- or created but does NOT update the archive bit. The second command
- updates the archive bit without doing anything else (no output file
- is specified and thus none is created). The second command goes
- extremely quickly since files are not actually read.
-
- For your INCREMENTAL backups, risking modifying the archive bit while
- backing the files up is feasible, Since very few files will be
- backed up (comparitively):
-
- backup -a -UA -c -d"*.o" volume: -ooutput
-
- In this case I use the -a option (append). You might NOT want to do
- this and save the incremental backups as separate files.
-
-
- (5)
- STANDARD METHOD OF RESTORING
-
- Restoring a backup to the original volume: (Restore or Backup -r)
-
- NOTE: If the -A option is specified, restored files will have
- their Archive bit cleared. If -A is NOT specified, files will have
- their archive bit set and will thus be re-backed up on the next
- incremental backup.
-
- NOTE: When restoring files, remember that the incremental backups
- will have the newest modifications and should be specified LAST:
-
- Restore completebkfile incr1 incr2 incr3....
-
- Partial Restore using -p:
-
- Restore -pstuffIWant bkfile1 bkfile2 bkfile3...
-
- ARCHIVE LISTING:
-
- Restore -t bkfile1 bkfile2....
-
- NOTE: Two 'sizes' are given in the listing. The first
- is the # bytes the file takes up in the archive, the
- second is the actual size of the file.
-
-
- (6)
- FLOPICAL BACKUP AND RESTORE
-
- There are two problems associated with floppy backup and restore:
-
- (1) A single file on the HD may be two big for a single floppy
- (2) It may take a lot of floppies to backup an HD
-
- Additionaly, one wants the following conveniences:
-
- (1) Be able to backup to a logical progression of (floppy) drives,
- inserted blank disks in while the system is working on other
- drives.
-
- (2) Be able to restore the same way
-
- (3) If one or more floppies is destroyed be able to restore from the
- remaining floppies.
-
- Currently, you can specify which devices to cycle through
- with the -F option (-Fdf0: -Fdf1: -Fdf2:), but BACKUP will
- always prompt you before continuing. Since it uses the
- console device, you can specify the yes response as many
- times as you have floppies in ready drives.
-
- Currently, files larger than the specified -f size (800K
- default) cannot be handled if using -f/-F ... However, by
- enabling compression larger files can still fit.
-
- Currently, the entire compressed result of a file must be
- able to fit into memory during the backup.
-
-
- ***
-
- BACKUP. Specify the -f option and then -Fvol: for each floppy
- drive (in the order you want) to backup to. Example:
-
- -f -Fdf0: -Fdf1:
-
- (Also keep in mind all the options listed in sections (3), (4), & (5))
- Currently, you must have PRE-FORMATTED all your backup disks since the
- backup/restore works through normal files. The system will prompt for
- readyness every time it completes a section.
-
- The backup process never deletes files, only creates or overwrites
- them. Thus, accidently sticking in a non-blank or incorrect backup
- disk will probably result in a disk-full requester.... not Fatal, though
- inconvenient.
-
- You must still specify the -o option to name the output file, which will
- be prefixed with the next -F volume in sequence and suffixed with the
- sequence number. (.nn) The disk labels for your floppies may all be
- the same.
-
- EXAMPLE:
-
- backup -c -d"*.o" -f -Fdf0: -Fdf1: -Fdf2: volume: -oxxbak
- backup -A volume:
-
- NOTE: You do NOT specifiy a volume prefix in the -o option ..
- those specified by -F are automatically cycled through as the
- prefix.
-
- * If your hard disk has enough space on it I suggest you backup to an
- alternate partition using only -f (not -F which forces user prompts),
- then copy the chunks to floppies after the entire backup has
- completed.
-
- ***
-
- RESTORE. Restore works the same way. EACH DISK IS INDEPENDANT! You
- may insert disks in any order to be restored. Simply execute the
- standard restore command in section (5) for each floppy.
-
- Destroyed disks may be skipped. Currently, no support for partially
- restored disks exists... i.e. the archive has be clean.
-
-
-
- SHAR_EOF
- # End of shell archive
- exit 0
- --
- Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
- Have five nice days.
-